package com.wang.mvchain.common.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component;

/**
 * 文件的相关工具类
 * @author wangsh
 *
 */
@Component("fileUtil")
public class FileUtil
{
	private Log log = LogFactory.getLog(FileUtil.class);
	
	/*匹配${}的正则,还有分组的概念*/
	private Pattern escapresource = Pattern.compile("(\\$\\{)([\\w]+)(\\})");

	private static final int buffsize = 16 * 1024;

	/**
	 * 拷贝图片,
	 * 
	 * @param source
	 * @param target
	 * @return
	 * @throws IOException 
	 */
	public boolean copyFile(File source, File target)
	{
		try {
			if(!target.getParentFile().exists())
			{
				//如果父目录不存在,就创建
				target.getParentFile().mkdirs();
			}
			
			BufferedInputStream bis = new BufferedInputStream(
					new FileInputStream(source));
			BufferedOutputStream bos = new BufferedOutputStream(
					new FileOutputStream(target));
			byte[] buff = new byte[2048];
			int leng = 0;
			while ((leng = bis.read(buff)) != -1)
			{
				bos.write(buff, 0, leng);
			}

			bis.close();
			bos.close();

			return true;
		} catch (IOException e) {
			log.error("拷贝文件失败了", e);
		}
		return false ; 
	}
	
	/**
	 * 拷贝图片,
	 * 
	 * @param source
	 * @param target
	 * @return
	 * @throws IOException 
	 */
	public boolean copyFile(String mimeType , InputStream is, OutputStream os)
	{
		if(!this.uploadFileFilter("file", mimeType))
		{
			return false ; 
		}
		try {
			BufferedInputStream bis = new BufferedInputStream(is);
			BufferedOutputStream bos = new BufferedOutputStream(os);
			byte[] buff = new byte[2048];
			int leng = 0;
			while ((leng = bis.read(buff)) != -1)
			{
				bos.write(buff, 0, leng);
			}

			bis.close();
			bos.close();

			return true;
		} catch (IOException e) {
			log.error("拷贝文件失败了", e);
		}
		return false ; 
	}
	
	/**
	 * 专门用来处理点位符
	 * @return
	 */
	public String replaceOperator(String source , Map<String, String> paramsMap)
	{
		if(paramsMap.size() == 0 )
		{
			return source ; 
		}
		
		StringBuffer sb = new StringBuffer();
		/*将${wangsh}的值替换掉*/
		Matcher matcher = this.escapresource.matcher(source);
		while(matcher.find())
		{
			if(paramsMap.get(matcher.group(2)) != null )
			{
				matcher.appendReplacement(sb, paramsMap.get(matcher.group(2))) ;
			}
		}
		
		matcher.appendTail(sb);
		
		return sb.toString() ; 
	}
	
	/**
	 * 读取某个文件的内容
	 * 并且为对象赋值,类似于资源文件
	 * 如${wangsh},map中键为wangsh的值放的是yanglp,会将整个${wangsh}替换为yanglp
	 * 
	 * @param sourceFile
	 * @param charset
	 * @param paramsMap 键为源文件中出现的,值为真正要替换的值
	 * @return
	 */
	public String readFile(File sourceFile , String charset ,
			Map<String, String> paramsMap)
	{
		if(charset == null || "".equalsIgnoreCase(charset))
		{
			charset = ConstatFinalUtil.CHARSET ; 
		}
		StringBuffer sb = new StringBuffer();
		try
		{
			BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(sourceFile) , charset));
			String line = "" ; 
			StringBuffer patressb = new StringBuffer();
			while((line = br.readLine()) != null )
			{
				line = line.trim() ; 
				patressb.append(line);
			}
			sb.append(this.replaceOperator(patressb.toString(), paramsMap));
			br.close();
		} catch (IOException e)
		{
			log.error("读取文件出错了", e);
		}
		return sb.toString() ; 
	}
	
	/**
	 * 读取某个文件的内容
	 * 并且为对象赋值,类似于资源文件
	 * 如${wangsh},map中键为wangsh的值放的是yanglp,会将整个${wangsh}替换为yanglp
	 * 
	 * @param sourceFile
	 * @param charset
	 * @param paramsMap 键为源文件中出现的,值为真正要替换的值
	 * @return
	 */
	public String readFile(InputStream is , String charset ,
			Map<String, String> paramsMap)
	{
		if(charset == null || "".equalsIgnoreCase(charset))
		{
			charset = ConstatFinalUtil.CHARSET ; 
		}
		StringBuffer sb = new StringBuffer();
		try
		{
			BufferedReader br = new BufferedReader(new InputStreamReader(is , charset));
			String line = "" ; 
			StringBuffer patressb = new StringBuffer();
			while((line = br.readLine()) != null )
			{
				line = line.trim() ; 
				patressb.append(line);
			}
			sb.append(this.replaceOperator(patressb.toString(), paramsMap));
			br.close();
		} catch (IOException e)
		{
			log.error("读取文件出错了", e);
		}
		return sb.toString() ; 
	}
	
	/**
	 * 对上传的文件进行过滤,
	 * 扩展名全部使用小写
	 * @param type 类型
	 * 			   photo
	 * @param fileName MIME类型
	 * @return true表示上传的文件合法,false表示上传的文件不合法
	 */
	public boolean uploadFileFilter(String type,String mime)
	{
		String [] fileExpand = null ; 
		if("file".equalsIgnoreCase(type))
		{
			//过滤图片
			fileExpand = ConstatFinalUtil.SYS_BUNDLE.getString("file.format").split(",");
		}
		
		for (int i = 0; i < fileExpand.length; i++)
		{
			String temp = fileExpand[i];
			if(mime.toLowerCase().equalsIgnoreCase(temp))
			{
				//上传文件合法
				return false ; 
			}
		}
		return true ; 
	}
	
	/**
	 * 读取某个文件的内容
	 * 并且为对象赋值,类似于资源文件
	 * 如${wangsh},map中键为wangsh的值放的是yanglp,会将整个${wangsh}替换为yanglp
	 * 
	 * @param sourceFile
	 * @param charset
	 * @param paramsMap 键为源文件中出现的,值为真正要替换的值
	 * @return
	 */
	public void writeFile(File sourceFile ,byte[] b)
	{
		if(!sourceFile.getParentFile().exists())
		{
			sourceFile.getParentFile().mkdirs() ; 
		}
		try
		{
			BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(sourceFile));
			bos.write(b);
			bos.close();
		} catch (IOException e)
		{
			log.error("读取文件出错了", e);
		}
	}
	
	/**
	 * 将文件内容写入到文件中
	 * 
	 * @param sourceFile
	 * @param charset
	 * @param paramsMap 键为源文件中出现的,值为真正要替换的值
	 * @return
	 */
	public void writeFile(File sourceFile ,String b)
	{
		if(!sourceFile.getParentFile().exists())
		{
			sourceFile.getParentFile().mkdirs() ; 
		}
		try
		{
			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(sourceFile) , ConstatFinalUtil.CHARSET));
			bw.write(b);
			bw.flush();
			bw.close();
		} catch (IOException e)
		{
			log.error("读取文件出错了", e);
		}
	}
	
	/**
	 * 压缩文件
	 */
	public void zipFile(List<File> fileList , OutputStream os)
	{
		byte[] b = new byte[buffsize] ; 
		int leng = 0 ; 
		try
		{
			// 压缩
			ZipOutputStream zos = new ZipOutputStream(os);
			
			for (Iterator iterator = fileList.iterator(); iterator.hasNext();)
			{
				File file = (File) iterator.next();
				
				 // 被压缩的文件
			    FileInputStream fis = new FileInputStream(file);
			    // 在压缩包中的路径
			    ZipEntry z1 = new ZipEntry(file.getName());
			    zos.putNextEntry(z1);
			    
			    while ((leng = fis.read(b)) != -1)
			   {
			      zos.write(b, 0, leng);
			   }
			   
			   fis.close();
			}
		}catch (IOException e)
		{
			ConstatFinalUtil.SYS_LOG.error("压缩文件出错了," + fileList, e);
		}
	}
	
	/**
	 * 将一个指定的文件拆分成多个文件
	 */
	public int fileSplit(File souFile, int size)
	{
		int count = 1 ; 
		int totalCount = 1 ; 
		try
		{
			String path = souFile.getPath() ;
			BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(souFile), ConstatFinalUtil.CHARSET));
			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path + "_" + count + path.substring(path.lastIndexOf("."), path.length())) , ConstatFinalUtil.CHARSET));
			String line = "" ;
			while((line = br.readLine()) != null)
			{
				bw.write(line);
				bw.newLine();
				if(totalCount % size == 0 )
				{
					bw.flush();
					bw.close();
					count ++ ; 
					bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path + "_" + count + path.substring(path.lastIndexOf("."), path.length())) , ConstatFinalUtil.CHARSET));
				}
				totalCount ++ ;
			}
			
			bw.flush();
			br.close();
			br.close();
		} catch (IOException e)
		{
			ConstatFinalUtil.SYS_LOG.error("拆分文件失败了!" + souFile, e);
		}
		return count ; 
	}
}
